Ygrid = {
	
	enhance: function(tab) {
		Yutil.ensureId(tab);
		
		var heads = Ygrid._getHeaderCells(tab);
		if (!heads) return false;
		
		// enhance each header, sortable & dragable
		for (var i = 0, n = heads.length; i < n; i++) {
			var h = heads[i];
			if (!"th".isTagOf(h)) alert("Tag of "+h.innerHTML+" must be 'th'!!");
			if ('no_en'.hasClass(h)) continue;
			if ((h.innerText || h.textContent || '').trim() == '') continue;
			
			h.innerHTML = 
				"<a class='ha' onclick='Ygrid.sort(this.parentNode); return false;' href='javascript:;'>"
				+ h.innerHTML
				+ "</a>";
			
			var ha = h.firstChild;
			if ('asc'.hasClass(h)) 'asc'.addClass(ha);
			if ('desc'.hasClass(h)) 'desc'.addClass(ha);
			
			ha.onDragStart = Ygrid.haOnDragStart;
			ha.onDragMove = Ygrid.haOnDragMove;
			ha.onDragEnd = Ygrid.haOnDragEnd;
			Ydragdrop.enhanceDragable(ha);
		}

		// controls for mod table
		if (tab.getAttribute('tableclass')) {
			tab.isMod = true;
			Ygrid.mod_createControls(tab);
		}

		// fixed header row
		if ('fit_to_parent'.hasClass(tab))
			Yutil.fitToParent(tab);
	},
	
	_getHeaderCells: function(tab) {
		var hrow = (tab.rows && tab.rows.length > 0) ? tab.rows[0] : null;
		return hrow ? hrow.cells : [];
	},
	
	sort: function(h) {
		var hrow = h.parentNode;
		var tbl = "table".enclosing(hrow);
		if ("no_sort".hasClass(tbl) || "no_sort".hasClass(h)) return;
		
		Yutil.showDisabledZone(tbl, 1000, "Sorting...");

		// disabled zone shows only with this trick
		setTimeout(function() { Ygrid._sort(h); }, 10);
	},

	_sort: function(h) {
		var hrow = h.parentNode;
		var tbl = "table".enclosing(hrow);
		var ha = h.firstChild;
		var asc = !"asc".hasClass(ha);
		var isNum = "number".hasClass(h);
		var isWY = "weekyear".hasClass(h);
		
		Yutil.showDisabledZone(tbl, 1000, "Sorting...");

		// get rows and data
		var tbody = tbl.tBodies[0], rows = tbody.rows;
		var newRows = [], ci = h.cellIndex, r;
		for (var i = 0, n = rows.length; i < n; i++) {
			if ((r = rows[i]) == hrow) continue;
			r.sortdata = (r.cells[ci].getAttribute('sortvalue') || r.cells[ci].innerText || r.cells[ci].textContent || '').trim().toLowerCase();
			if (isNum)
				r.sortdata = r.sortdata.length == 0 ? 0 : parseFloat(r.sortdata.replace(/[^\-0-9.]/g,''), 10);
			if (isWY)
				r.sortdata = parseInt(r.sortdata.substring(3, 7) + r.sortdata.substring(0,2));
			r.origpos = i;
			newRows.push(r);
		}
		
		// sort and update table
		newRows.sort(asc ? Ygrid._compare : Ygrid._compare_rvs);
		for (var i = 0, n = newRows.length; i < n; i++)
			tbody.appendChild(newRows[i]);
		var rows = tbody.rows;
		for (var r = 0, n = rows.length; r < n; r++) {
			if (r % 2 == 0)
				'odd'.removeClass(rows[r]);
			else
				'odd'.addClass(rows[r]);
		}
		
		// update arrow on header
		var allha = "th/a.ha".resolve(hrow);
		for (var i = 0, n = allha.length; i < n; i++) {
			allha[i].className = "ha";
		}
		ha.className += asc ? " asc" : " desc";

		Yutil.hideDisabledZone(tbl, 1000);
		if (tbl.isMod) Ygrid.mod_onLayoutChange(tbl);
	},
	
	_compare: function(a, b) {
		if (a.sortdata == b.sortdata)
			return a.origpos - b.origpos; // keep orig position
		return a.sortdata < b.sortdata ? -1 : 1;
	},
	
	_compare_rvs: function(a, b) {
		if (a.sortdata == b.sortdata)
			return a.origpos - b.origpos; // keep orig position
		return a.sortdata < b.sortdata ? 1 : -1;
	},
	
	haOnDragStart: function(event) {
		var m = $('grid_ins_mark');
		if (!m) {
			m = "<div id='grid_ins_mark'></div>".createElement();
			document.body.appendChild(m);
		}
	},
	
	haOnDragMove: function(newPos, event) {
		// find new col position
		var allh = this.parentNode.parentNode.cells, h;
		var px = event.clientX;
		var min = 99999, d, col, hp;
		var markPos;
		for (var i = 0, n = allh.length; i < n; i++) {
			h = allh[i];
			hp = Yutil.abspos(h);
			d = Math.abs(hp[0] - px);
			if (d < min) {
				min = d;
				col = i;
				markPos = hp;
			}
		}
		hp = [hp[0] + h.offsetWidth, hp[1]];
		d = Math.abs(hp[0] - px);
		if (d < min) {
			min = d;
			col = allh.length;
			markPos = hp;
		}
		
		// show insert mark
		Yutil.moveTo($('grid_ins_mark'), markPos[0]-6, markPos[1]-7);
		
		this.newCellIndex = col;
	},
	
	haOnDragEnd: function() {
		Yutil.moveTo(this, 0, 0);
		
		// clear insert mark
		Yutil.moveTo($('grid_ins_mark'), -10, -10);
		
		// need to move col ?
		var col = this.newCellIndex, oCol = this.parentNode.cellIndex;
		var allh = this.parentNode.parentNode.cells;
		if (col == this.cellIndex || col+1 == this.cellIndex)
			return; // no col change
		
		// move col
		var tbl = 'table'.enclosing(this);
		Yutil.showDisabledZone(tbl, 1000, "Moving...");

		// disabled zone shows only with this trick
		setTimeout(function() { Ygrid._moveCol(tbl, oCol, col); }, 10);
	},
	
	_moveCol: function(tbl, oCol, col) {
		var rows = tbl.rows, r;
		var isLast = col >= rows[0].cells.length;
		for (var i = 0, n = rows.length; i < n; i++) {
			r = rows[i];
			r.insertBefore(r.cells[oCol], isLast ? null : r.cells[col]);
		}

		Yutil.hideDisabledZone(tbl, 1000);
		if (tbl.isMod) Ygrid.mod_onLayoutChange(tbl);
	},
	
	mod_createControls: function(tab) {
		var rci = Yutil.remoteCallInfo(tab);
		var args = '"'+rci.url.trimAfter('?')+'", "'+rci.target.id+'", "'+tab.id+'"';
		var ctrls = (
			"<div id='"+tab.id+"_controls' class='grid_controls'>" +
				"<div class='l'>" +
					"<a onclick='Ygrid.mod_saveLayout("+args+")' class='star_yellow hidden' href='javascript:;'>Save layout</a>" +
				"</div>" +
				"<div class='r'>" +
					"<a onclick='Ygrid.mod_customizeTable("+args+")' href='javascript:;'>Customize table...</a>" +
				"</div>" +
			"</div>"
		).createElement();
		
		tab.style.clear = 'both';
		tab.parentNode.insertBefore(ctrls, tab);

		var minCtrlWidth = ctrls.childNodes[0].offsetWidth + ctrls.childNodes[1].offsetWidth;
		ctrls.style.width = (Math.min(ctrls.offsetWidth, Math.max(tab.offsetWidth, minCtrlWidth))) + 'px';
	},
	
	mod_customizeTable: function(pageUrl, pageDiv, tableId) {
		Yutil.disposeDialog('modtable_dialog');
		Ygrid.mod_checkModTableDialog();
		
		$('modtable_dialog_content').innerHTML = '';
		Yutil.showDialog('modtable_dialog');
		
		var url = '/young/web/ysp/modtable_edit.jspx';
		url += '?_M_=vedit';
		url += '&_P_=v' + encodeURIComponent(pageUrl+'?modpageTimestamp='+$(pageDiv).modpageTimestamp);
		url += '&_P_=v' + pageDiv;
		url += '&_P_=v' + encodeURIComponent($(tableId).getAttribute('tableclass'));
		url += '&_P_=v' + encodeURIComponent($(tableId).className);
		Yutil.remoteCall('', url, 'modtable_dialog_content');
	},
	
	mod_saveLayout: function(pageUrl, pageDiv, tableId) {
		Ygrid.mod_checkModTableDialog();
		
		var posts = '';
		var tbl = $(tableId);
		var hcells = Ygrid._getHeaderCells(tbl);
		var h, ha, colclass, colsort;
		posts += "<input name='tableclass' value='"+tbl.getAttribute('tableclass')+"' type='hidden'/>";
		for (var i = 0; i < hcells.length; i++) {
			h = hcells[i]; ha = h.firstChild;
			colclass = h.getAttribute('colclass') || (h.innerText || h.textContent || '').trim();
			if (!colclass) continue;
			posts += "<input name='colclass' value='"+colclass+"' type='hidden'/>";
			if (!ha) continue;
			colsort = 'asc'.hasClass(ha) || 'desc'.hasClass(ha) || '';
			if (colsort) {
				colsort = colclass + ':' + colsort;
				posts += "<input name='colsort' value='"+colsort+"' type='hidden'/>";
			}
		}
		$('modtable_dialog_content').innerHTML = posts;
		
		var url = pageUrl+'?modpageTimestamp='+$(pageDiv).modpageTimestamp;
		url += '&_M_=vupdateModifier';
		url += '&_P_=null';
		url += '&_P_=vtrue';
		Yutil.remoteCall('modtable_dialog_content', url, pageDiv);
	},
	
	mod_onLayoutChange: function(tab) {
		$(tab.id+'_controls').firstChild.firstChild.style.display = 'block';
	},
	
	mod_checkModTableDialog: function() {
		if (!$('modtable_dialog')) {
			Yutil.createDialog('modtable_dialog', '50em', '95%', 'Customize table');
		}
	}
}
Yutil.en.register('table.grid', Ygrid.enhance);
